package com.da.core;

import com.da.exception.PluginException;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

/**
 * @author da
 * @time 2024/7/11 下午 2:26
 * 自定义类加载器
 */
public class CustomClassLoader extends ClassLoader {
    /**
     * * jar包路径
     */
    private final String jarPath;

    public CustomClassLoader(String jarPath) {
        this.jarPath = jarPath;
    }

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        try {
            byte[] classData = getClassData(name);
            if (classData == null) {
                throw new ClassNotFoundException();
            }
            return defineClass(name, classData, 0, classData.length);
        } catch (PluginException e) {
            throw new ClassNotFoundException();
        }
    }

    /**
     * * 加载类数据
     * @param className 类名
     * @return 字节数组
     */
    private byte[] getClassData(String className) {
        String path = className.replace('.', '/').concat(".class");
        try (JarFile jarFile = new JarFile(jarPath)) {
            Enumeration<JarEntry> entries = jarFile.entries();
            while (entries.hasMoreElements()) {
                JarEntry entry = entries.nextElement();
                if (!entry.isDirectory() && entry.getName().equals(path)) {
                    InputStream is = jarFile.getInputStream(entry);
                    ByteArrayOutputStream baos = new ByteArrayOutputStream();
                    int bufferSize = 4096;
                    byte[] buffer = new byte[bufferSize];
                    int bytesRead;
                    while ((bytesRead = is.read(buffer)) != -1) {
                        baos.write(buffer, 0, bytesRead);
                    }
                    return baos.toByteArray();
                }
            }
        } catch (IOException e) {
            throw new PluginException(e);
        }
        return null;
    }
}
